# -*- coding:utf-8 -*-
"""
数据统计
"""
import logging

from PyQt5.QtCore import QObject, QThread, pyqtSignal

from LibrarySystem.services.interface.stats_service_interface import StatsServiceInterface
from LibrarySystem.repositories.mongodb.RepositoryHelper import RepositoryHelper

module_logger = logging.getLogger("logger")


class StatsService(StatsServiceInterface):
    """
    @ClassName：StatsService
    @Description： 继承 统计业务层接口类，本项目只创建一个实例
    负责实现启动线程进行 图书信息统计，包括借阅情况，图书种类，出版时间等信息
    --------------------------------------------------
    此类编写请注意，不要将
    self.worker_1 = Worker(keywords=keywords)
    self.thread_1 = QThread()
    提升到 __init__() 进行初始化，他不会工作的
    也不要不添加 self，下面的也不会工作
    --------------------------------------------------
    创建实例
    worker_1 = Worker(keywords=keywords)
    thread_1 = QThread()
    将 Worker 加入  QThread 管理
    worker_1.moveToThread(self.thread_1)
    --------------------------------------------------
    @Author：锦沐Python
    """
    def __init__(self):
        # 线程运行标识，阻止短时间内多次触发和创建线程，为 True 时允许启动线程
        self.calculate_1_tag = True
        self.thread_1 = None
        self.worker_1 = None

        self.calculate_2_tag = True
        self.thread_2 = None
        self.worker_2 = None

        self.calculate_3_tag = True
        self.thread_3 = None
        self.worker_3 = None

    def calculate_match_case_by_keywords_thresd(self, accept_data_func, keywords):
        """
        根据关键词查找书籍，统计借阅信息，与关键词相关的图书名称，限制最大数量为 10个
        @param accept_data_func: 槽函数引用
        @param keywords: 关键词
        :信号发送: (all_num, borrowed_num, book_name_list)
        """
        if self.calculate_1_tag:
            module_logger.info("线程1启动")
            self.calculate_1_tag = False
            self.thread_1 = QThread()
            self.worker_1 = Worker(keywords=keywords)
            self.worker_1.moveToThread(self.thread_1)

            # 连接耗时操作
            self.thread_1.started.connect(self.worker_1.calculate_borrowing_and_match_case_by_keywords)
            self.worker_1.data_signal.connect(accept_data_func)
            self.worker_1.finally_signal.connect(self._set_calculate_tag)
            self.thread_1.start()

        else:
            module_logger.info("线程1锁定，稍后再试")

    def calculate_user_case_thresd(self, accept_data_func, user_id):
        """
        用户权限查看，用户借阅的书籍种类数量情况，借阅历史
        @param accept_data_func: 槽函数引用
        @param user_id: 普通用户id
        """

        if self.calculate_2_tag:
            module_logger.info("线程2启动")
            self.calculate_2_tag = False
            self.thread_2 = QThread()
            self.worker_2 = Worker(user_id=user_id)
            self.worker_2.moveToThread(self.thread_2)
            self.thread_2.started.connect(self.worker_2.calculate_user_case)
            self.worker_2.data_signal.connect(accept_data_func)
            self.worker_2.finally_signal.connect(self._set_calculate_tag)
            self.thread_2.start()

        else:
            module_logger.info("线程2锁定，稍后再试")

    def calculate_admin_case_thresd(self, accept_data_func):
        """
        管理员权限可查看，
        @param accept_data_func: 槽函数引用
        """

        if self.calculate_3_tag:
            module_logger.info("线程3启动")
            self.calculate_3_tag = False
            self.thread_3 = QThread()
            self.worker_3 = Worker()
            self.worker_3.moveToThread(self.thread_3)
            self.thread_3.started.connect(self.worker_3.calculate_admin_case)
            self.worker_3.data_signal.connect(accept_data_func)
            self.worker_3.finally_signal.connect(self._set_calculate_tag)
            self.thread_3.start()

        else:
            module_logger.info("线程3锁定，稍后再试")

    def _set_calculate_tag(self):
        module_logger.info("线程状态激活")
        self.calculate_1_tag = True
        self.calculate_2_tag = True
        self.calculate_3_tag = True
        if self.thread_1 and self.thread_1.isRunning():
            self.thread_1.quit()
            self.thread_1.wait()
        if self.thread_2 and self.thread_2.isRunning():
            self.thread_2.quit()
            self.thread_2.wait()
        if self.thread_3 and self.thread_3.isRunning():
            self.thread_3.quit()
            self.thread_3.wait()


class Worker(QObject):
    """
    @ClassName：Worker
    @Description：
    负责实现 图书信息统计算法，并返回结果，包括借阅情况，图书种类，出版时间等信息
    @Author：锦沐Python
    """
    # 结束运算信号，用于通知 StatsService 反转线程标志
    finally_signal = pyqtSignal()
    # 数据传输信号，将结果传递给视图层 定义的槽函数 accept_data_func
    data_signal = pyqtSignal(tuple)

    def __init__(self, keywords="", user_id=""):
        super().__init__()
        self.keywords = keywords
        self.user_id = user_id

    def calculate_borrowing_and_match_case_by_keywords(self):
        """
        根据关键词查找书籍，统计书籍借阅情况，以及匹配的图书名称，最大 10 个参数
        :return: (all_num, borrowed_num, book_name_list)
        """
        module_logger.info("线程开始计算")
        # 定义一个包含需要检查字段的集合
        fields_to_check = ["book_name", "book_id", "category", "author"]

        (flag, book_list) = RepositoryHelper.get_book_repository().get_books_by_keywords(fields_to_check=fields_to_check, keywords=self.keywords)

        if flag is False:
            msg = book_list
            self.data_signal.emit((False, msg))
            self.finally_signal.emit()
            module_logger.info("线程无法获取图书信息")
            return

        all_num = len(book_list)
        # 数量限制
        count_limt = 20
        book_name_list = []
        borrowed_num = 0

        # 遍历书籍信息
        for book in book_list:
            if book.borrowed_by:
                borrowed_num += 1
            # 收集相关词
            if len(book_name_list) < count_limt:
                book_name_list.append(book.book_name)

        self.data_signal.emit((True, (all_num, borrowed_num, book_name_list)))
        self.finally_signal.emit()
        module_logger.info("关键词统计完成计算")

    # 用户借阅统计,
    def calculate_user_case(self):
        """
        用户借阅的书籍种类数量情况，借阅历史，最大 10 个参数
        @return: (category_name_and_num, date_list, book_name_list)
        """

        # 获取书籍信息
        (flag, book_list) = RepositoryHelper.get_book_repository().get_books_by_column(column="borrowed_by", value=self.user_id)
        if flag is False:
            msg = book_list
            self.data_signal.emit((False, msg))
            self.finally_signal.emit()
            module_logger.info("线程无法获取图书信息")
            return

        category_list = set()
        category_name_and_num = {}
        date_list = []
        book_name_list = []

        count_limt = 20
        # 统计与用户相关的书籍
        for book in book_list:
            # 统计图书类别
            if book.category in category_list:
                category_name_and_num[book.category] += 1
            else:
                category_name_and_num[book.category] = 1

            # 找到 count_limt 个就停
            if len(category_list) >= count_limt or \
                    len(date_list) >= count_limt or \
                    len(book_name_list) >= count_limt:
                break

            category_list.add(book.category)
            date_list.append(book.borrow_time)
            book_name_list.append(book.book_name)

        # 将两个列表组合成元组列表
        combined_list = list(zip(date_list, book_name_list))

        # 根据 date_list 中的时间进行排序
        sorted_combined_list = sorted(combined_list, key=lambda x: x[0], reverse=False)

        # 分离排序后的列表
        sorted_date_list = [item[0] for item in sorted_combined_list]
        sorted_book_name_list = [item[1] for item in sorted_combined_list]

        self.data_signal.emit((True, (category_name_and_num, sorted_date_list, sorted_book_name_list)))
        self.finally_signal.emit()
        module_logger.info("用户统计完成计算")

        # 用户借阅统计,

    def calculate_admin_case(self):
        """
        图书种类及数量，借阅情况，出版时间与书籍数量，最大 10 个参数
        @return:(category_name_and_num, all_num, borrowed_num, publication_date_and_num)
        """
        # 获取书籍信息
        module_logger.info("线程开始计算")
        (flag, book_list) = RepositoryHelper.get_book_repository().get_books(-1)
        if flag is False:
            msg = book_list
            self.data_signal.emit((False, msg))
            self.finally_signal.emit()
            module_logger.info("线程无法获取图书信息")
            return

        all_num = len(book_list)
        borrowed_num = 0
        # 类型
        category_list = set()
        category_name_and_num = {}

        # 出版时间
        publication_date_list = set()
        publication_date_and_num = {}

        # 数量限制,显示排名前10
        max_count = 10

        for book in book_list:
            if book.borrowed_by:
                borrowed_num += 1

            # 统计图书类别
            if book.category in category_list:
                category_name_and_num[book.category] += 1
            else:
                category_name_and_num[book.category] = 1

            # 统计图书出版年份与数量
            if book.publication_date in publication_date_list:
                publication_date_and_num[book.publication_date] += 1
            else:
                publication_date_and_num[book.publication_date] = 1

            category_list.add(book.category)
            publication_date_list.add(book.publication_date)

        sorted_items = sorted(category_name_and_num.items(), key=lambda x: x[1], reverse=True)
        category_name_and_num = dict(sorted_items[:max_count])
        sorted_items = sorted(publication_date_and_num.items(), key=lambda x: x[1], reverse=True)
        publication_date_and_num = dict(sorted_items[:max_count])

        self.data_signal.emit((True, (category_name_and_num, all_num, borrowed_num, publication_date_and_num)))
        self.finally_signal.emit()
        module_logger.info("管理员统计完成计算")
